import plugin from '../../lib/plugins/plugin.js'
import axios from 'axios'
import request from 'request'
import _ from 'lodash'
import fs from 'fs'
let uploadRecord = ''
let model = "gpt-4-8k" //AI模型目前coze限制每个用户每天128k只能调用50次，8k100次
let botsender = true

//导入其他插件的高清语音合成
if (fs.existsSync('plugins/hs-qiqi-plugin/model/uploadRecord.js')) {
  uploadRecord = (await import("../../plugins/hs-qiqi-plugin/model/uploadRecord.js")).default
} else if (fs.existsSync('plugins/earth-k-plugin/model/uploadRecord.js')) {
  uploadRecord = (await import("../../plugins/earth-k-plugin/model/uploadRecord.js")).default
} else {
  uploadRecord = 0
}

/**
本插件基于coez.js重构
增加了频道添加，完美的隔离对话
重写参数传递相关代码
**/

let yuhec = 0 //语音合成开关 0为关闭 1为开启
let group_id = " "
let api_key = " "
//这里替换为你的coze代理api
let url = ' '
//这里写coze的请求密钥
let secret = " "

let audit = 0 //审核开关 0为关闭 1为开启
let baidu_ak = " "
let baidu_sk = " "

//正则表达式列表，可以自行更改
//用来提取(判断)图片链接的正则表达式，
let regex = /(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|bmp|webp|jpeg)/g;
//去除图片链接
let regex1 = /((https?:\/\/[^\s]+\.(?:png|jpg|bmp|gif|jpeg|webp))|(!\[Image\]\(https?:\/\/[^\s]+\)))/g
//去除()[]等一系列括号，用来语音合成
let reqex2 = /\[.*?\]|【.*?】|\(.*?\)|（.*?）|［.*?］|〖.*?〗|https?:\/\/.*\.(jpg|png|jpeg|bmp|gif|webp)/g


export class COZE extends plugin {
    constructor () {
      super({
        name: 'coze',
        dsc: "coze，再配合语音合成",
        event: 'message',
        priority: 60000,
        rule: [
          {
            reg: "^#扣子结束对话",
            fnc: "coze_del"
          },
          {
            reg: "^#画图(.*)",
            fnc: "huatu"
          },
          {
            reg: "^#设置人设(.*)",
            fnc: 'szrs'
          },
          {
            reg: "^#设置唤醒词",
            fnc: "Wakeup"
          },
          {
            reg: "^#切换语音合成角色(.*)",
            fnc: "Synthesis"
          },
          {
            reg: '^.*(.*)',
            fnc: 'coze',
            log: false
          }
        ]
      })
    }
    
    async coze(e) {        
        //获取用户数据库
        let key = await redis.get(`COZE:DATA:${e.user_id}`)        
        //添加用户数据库
        if(!key) {
            let userData = {
                "createchannel": false,
                "channelID": 0,
                "wakeup": null,
                "QQ": e.user_id,
                "HumanDesign": null
            }
            await redis.set(`COZE:DATA:${e.user_id}`, JSON.stringify(userData))
        }
        
        let isNameKeyExists = e.message.some(({ image }) => image !== undefined);
        if(!isNameKeyExists) {
            return false
        }
        
        /**判断用户发送的文字是否带有指令**/
        let Wakeup = await redis.get(`COZE:DATA:${e.user_id}`)      
        let message = ""
        if(Wakeup) {
            let Object = JSON.parse(Wakeup)
            if(Object.QQ == e.user_id) {               
                let instruction = (Object.wakeup != null) ? Object.wakeup : "#c"
                if(e.msg.includes(instruction)) {
                    message = _.trimStart(e.msg, instruction)
                } else {
                    return false
                }
            }
        }
        
        
        logger.info(`调用扣子：${message}`)     
        
        if(audit == 1) {
            let ContentAudit = await Audit(message)
            if(ContentAudit.conclusion != "合规") {
                return e.reply("你的提问未通过内容审核，现已拦截提问请求，请重新组织语言", true)
            }
        }
        
        //获取用户是否有频道如果没有就创建
        let key1 = await redis.get(`COZE:DATA:${e.user_id}`)
        let Object = JSON.parse(key1)
        if(Object.createchannel == false) {
            let response = await Channelcreation("creation", e.user_id)
            if(response.code != 200) {
                return e.reply(response.message)
            }
        }
              
        //图片链接获取
        let img = []
        if (e.source) {
            let source
            if (e.isGroup) {
                source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
            } else {
                source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
            }
            for (let i of source.message) {
                if (i.type == 'image') {
                    img.push(i.url)
                }
            }
        } else {
            img = e.img
        }
        //如果信息包含图片
        let Content = ""
        if (_.isEmpty(img) == false) {
            Content = `${message}，[${img[0]}]`
        } else if (_.isEmpty(img)) {
            Content = message
        }
        
        //创建参数
        let key2 = await redis.get(`COZE:DATA:${e.user_id}`)
        let Object1 = JSON.parse(key2)
        let coze_Data = {
            "channelId": Object1.channelID,
            "stream": false,
            "model": model,
            "messages": [{ 'role': 'user', 'content': Content }]
        }
        
        
        //扣子请求
        let response = await coze_api(coze_Data)
        
        if(response.code != 200) {
            return e.reply(response.message)
        }
               
        let result = regex.test(response.Message);
        if(result) {
            //获取图片数量
            let match, urls = [];
            while (match = regex.exec(response.Message)) {
                urls.push(match[0]);
            }
            logger.info(urls)
            
            if(urls.length > 1) {
                let msgList = []
                const forwarder = 
                botsender
                  ? { nickname: Bot.nickname, user_id: Bot.uin }
                  : {
                    nickname: this.e.sender.card || this.e.user_id,
                    user_id: this.e.user_id,
                  };
                  for(let i = 0; i <= urls.length; i++) {
                    msgList.push({
                        message: segment.image(urls[i]),
                        ...forwarder,
                    });
                  }
                let cleanedText = response.Message.replace(regex1, '')
                await e.reply(await e.group.makeForwardMsg(msgList))
                await e.reply(`${cleanedText}`, true)
            } else if(urls.length == 1) {
                let cleanedText = response.Message.replace(regex1, '')
                let MSG = [
                    cleanedText,
                    segment.image(urls[0]),
                ];
                e.reply(MSG, true)
            }
        } else {
            e.reply(`${response.Message}`, true)
        }       
        
        //语音合成
        if(yuhec == 1) {
            let synthesis = await Voice(response.Message)
            if(synthesis.code == 200) {                
                let msg = await uploadRecord(synthesis.voicecul, 0, false)
                return e.reply(msg)
            } else if(synthesis.code != 200) {
                return e.reply(`语音合成失败\n${synthesis.detail}`)
            }
        }        
        return true        
    }
    
    async coze_del(e) {
        let key = await redis.get(`COZE:DATA:${e.user_id}`)
        let Object = JSON.parse(key)
        if(Object.createchannel == true) {
            let response = await Channelcreation("del", e.user_id)
            if(response.code == 200) {
                return e.reply("已清空聊天记录，开始新的对话请使用 #c+内容 指令")
            } else {
                return e.reply(response.message)
            }
        }
    }
    
    async Wakeup(e) {
        this.setContext('doRep')
        await this.reply("请发送自定义唤醒词\n唤醒词建议不大于3个字最好是1个字到两个字\n请不要包含特殊符号\n为了不误触建议你再唤醒词前加上#，/的符号\n例如 #扣子 或 /扣子")
        return true
    }
    
    /**开始监听上下文**/
    async doRep() {
        try{
            let key = await redis.get(`COZE:DATA:${this.e.user_id}`)
            if(!key) {
                let userData = {
                    "createchannel": false,
                    "channelID": 0,
                    "wakeup": null,
                    "QQ": this.e.user_id,
                    "HumanDesign": null
                }
                await redis.set(`COZE:DATA:${this.e.user_id}`, JSON.stringify(userData))
            }
            
            let key1 = await redis.get(`COZE:DATA:${this.e.user_id}`)
            if(key) {
                let Object = JSON.parse(key1)
                Object.wakeup = this.e.msg
                await redis.set(`COZE:DATA:${this.e.user_id}`, JSON.stringify(Object))
                this.finish('doRep')
                await this.e.reply(`唤醒词设置成功！\n『${this.e.msg}』 将是你的专属唤醒词\n${this.e.msg}你好\n发送以上指令来和AI对话吧！`)
                return
            }
        } catch (error) {
            logger.error(error)
            this.finish('doRep')
        }
    }
}

//调用扣子
async function coze_api(Data) {     
    try {
        let headers = {
            'Content-Type': 'application/json', // 设置内容类型为JSON
            'Authorization': `Bearer ${secret}`, // 添加JWT令牌或其他身份验证信息
        };
              
        let response
        if(!secret) {
            response = await axios.post(`${url}/v1/chat/completions`, Data);
        } else if(secret) {
            response = await axios.post(`${url}/v1/chat/completions`, Data, { headers: headers});
        }
        
        let message = response.data.choices[0].message.content
        return { code: 200, Message: message }
    } catch (error) {
        logger.error(error)
        return { code: 500, message: error.response.data.error.message }
    }    
}

//频道创建
async function Channelcreation(type, userId) {
    let key = await redis.get(`COZE:DATA:${userId}`)
    let Object = JSON.parse(key)
    let headers = {
        "proxy-secret": secret
    }
    try {
        if(type == "creation" && Object.createchannel == false) {
            let data = {
                "name": String(userId)
            }
            let response
            if(!secret) {
                response = await axios.post(`${url}/api/channel/create`, data)
            } else if(secret) {
                response = await axios.post(`${url}/api/channel/create`, data, { headers: headers })
            }
            
            let jsonData = response.data
            if(jsonData.success == true) {
                //把频道ID写入用户数据库
                Object.channelID = jsonData.data.id
                Object.createchannel = true
                await redis.set(`COZE:DATA:${userId}`, JSON.stringify(Object))
                return { code: 200 }
            } else if(jsonData.success = false) {
                return { code: 403, message: jsonData.message }
            }
        } else if(type == "del" && Object.createchannel == true) {
            let response
            
            if(!secret) {
                response = await axios.get(`${url}/api/channel/del/${Object.channelID}`)
            } else if(secret) {
                response = await axios.get(`${url}/api/channel/del/${Object.channelID}`, { headers: headers })
            }
            
            if(response.data.success == true) {
                Object.channelID = 0
                Object.createchannel = false
                await redis.set(`COZE:DATA:${userId}`, JSON.stringify(Object))
                return { code: 200 }
            } else {
                return { code: 500, message: error.response.data.error.message }
            }
        }
    } catch (error) {
        logger.error(error.response.data)
        return { code: 500, message: error.response.data.message }
    }
}

//语音合成
async function Voice(msg) {
    let cleanedText = msg.replace(reqex2, '');
    let voiveurl =  `https://api.minimax.chat/v1/t2a_pro?GroupId=${group_id}`
    let headers = {
      "Authorization": `Bearer ${api_key}`,
      "Content-Type": "application/json",
    }

    let Data = {
      'text': cleanedText,
      'model' : 'speech-01',
      'audio_sample_rate': 32000,
      'bitrate': 128000,
      'timber_weights': [
        {
          'voice_id': 'female-tianmei',
          'weight': 100
        }
      ]
    }
    logger.info(`开始合成\n${cleanedText}`)
    try {
      let response = await axios.post(voiveurl, Data, { headers })
      if(!response.data.audio_file) {
        return { code: 1004, message: "语音合成失败", detail: response.data.base_resp.status_msg }
      }
      return { code: 200, voicecul: response.data.audio_file }
    } catch (error) {
      logger.error(error)
      return { code: 300, message: "语音调用失败", detail: error.response.data }
    }
}

//内容审核
async function Audit(Message) {
    let accessToken = await getAccessToken();
    let options = {
        'method': 'POST',
        'url': 'https://aip.baidubce.com/rest/2.0/solution/v1/text_censor/v2/user_defined?access_token=' + accessToken,
        'headers': {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        },
        form: {
            'text': Message
        }
    };
    return new Promise((resolve, reject) => {
        request(options, (error, response) => {
            if(error) {
                reject(error)
            } else {
                resolve(JSON.parse(response.body))
            }
        })
    })
}

async function getAccessToken() {
    let options = {
        'method': 'POST',
        'url': 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + baidu_ak + '&client_secret=' + baidu_sk,
    }
    return new Promise((resolve, reject) => {
        request(options, (error, response) => {
            if (error) { reject(error) }
            else { resolve(JSON.parse(response.body).access_token) }
        })
    })
}